﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Midgard
{
    enum enemyTexture
    {
        Thor,
        Ship,
        LittleShip,
        Wizard
    }

    enum shotTexture
    {
        Hammer,
        Bigshot,
        Littleshot,
        Fireball,
        Lightning
    }

    class EnemyManager
    {
        const float MIN_SPEED = 2.0f;
        const float MAX_SPEED = 8.0f;
        public const int PLAYFIELD_LOWER_BOUND = 550;
        public const int PLAYFIELD_UPPER_BOUND = 140;
        const int MAX_ENEMIES = 20;
        const int MIN_SHOT_SPEED = 5;
        const int MAX_SHOT_SPEED = 10;
        const int DAMAGE = 10;
        const int WIZARD_CHANCE = 30;
        const int WIZARD_SPEED_BONUS = 3;
        const int WIZARD_DAMAGE = 20;
        const int WIZARD_OFFSET = 70;
        const int LITTLE_CHANCE = 60;
        const int THOR_LEVEL = 4;
        const int WIZZARD_LEVEL = 2;
        const int LITTLE_LEVEL = 1;
        const int DIFF_TIME = 15;

        public bool thorActive;
        bool thorAlive = false;
        int maxThor = 0;
        int activeThors = 0;

        public bool HardMode = false;

        Player player;
        bool isActive;
        List<Enemy> enemies;
        List<Enemy> newlyDead;
        List<Enemy> deadList;
        float timeSinceLastAdded;
        float maxTimeSpaceing = 2;
        float minTimeSpaceing = 1;
        double timeSinceLastIncrease = 0;
        bool littleActive = false;
        bool wizardActive = false;
        int difficultyLevel = 0;
        Random rnd;
        List<Enemy> removalList;
        Rectangle viewport;
        SoundsManager soundsManager;
        //Texture2D ship;
        //Texture2D bullet;
        //Texture2D wizard;
        //Texture2D fireball;
        //Texture2D littleShip;
        //Texture2D littleBullet;
        Dictionary<enemyTexture, Texture2D> eTexture;
        Dictionary<shotTexture, Texture2D> sTexture;

        List<Projectile> projectiles;

        public List<Projectile> PendingProjectiles
        {
            get { return projectiles; }
        }

        public List<Enemy> DeadList
        {
            get { return newlyDead;}
        }

        /// <summary>
        /// Gives a list of the currently active enemies since last update
        /// </summary>
        public List<Enemy> ActiveEnemies
        {
            get { List<Enemy> active = new List<Enemy>();
                foreach (Enemy item in enemies)
                {
                if (item.State == EnemyState.Active)
                    active.Add(item);
                }
                return active;
            }
        }

        /// <summary>
        /// is the manager activly creating and managing enemies
        /// </summary>
        public bool IsActive
        {
            get { return isActive; }
            set { isActive = value; }
        }

        /// <summary>
        /// creates a new enemy manager
        /// </summary>
        /// <param name="viewport"> rectangle of the viewport</param>
        /// <param name="ship">ship sprite</param>
        public EnemyManager(Player player, Rectangle viewport, Dictionary<enemyTexture,Texture2D> EnemyTextures, Dictionary<shotTexture,Texture2D> ShotTextures)//Texture2D ship, Texture2D bullet, Texture2D wizard, Texture2D fireball,
            //Texture2D littleShip, Texture2D littleBullet)
        {
            this.player = player;
            isActive = false;
            enemies = new List<Enemy>();
            deadList = new List<Enemy>();
            timeSinceLastAdded = 0.0f;
            rnd = new Random();
            removalList = new List<Enemy>();
            this.viewport = viewport;
            //this.ship = ship;
            projectiles = new List<Projectile>();
            //this.bullet = bullet;
            //this.wizard = wizard;
            //this.fireball = fireball;
            //this.littleShip = littleShip;
            //this.littleBullet = littleBullet;
            newlyDead = new List<Enemy>();
            eTexture = EnemyTextures;
            sTexture = ShotTextures;
        }
        public void linkSoundManager(ref SoundsManager SoundsManager)
        {
            soundsManager = SoundsManager;
        }
        public void update(GameTime gameTime)
        {
            if (isActive)
            {
                
                timeSinceLastIncrease += gameTime.ElapsedGameTime.TotalSeconds;
                //Console.WriteLine(timeSinceLastIncrease);

                if (timeSinceLastIncrease > DIFF_TIME)
                {
                    
                    timeSinceLastIncrease = 0;
                    difficultyLevel++;
                    Console.WriteLine("Increading difficulty to " + difficultyLevel);

                    if (difficultyLevel >= LITTLE_LEVEL)
                    {
                        littleActive = true;
                    }

                    if (difficultyLevel >= WIZZARD_LEVEL)
                    {
                        wizardActive = true;
                    }
                    if (difficultyLevel % THOR_LEVEL == 0 && !thorAlive)
                    {
                        maxThor = difficultyLevel / THOR_LEVEL;
                        thorActive = true;
                        Console.WriteLine("THOR ACTIVATED");
                    }
                }

                foreach (Enemy item in newlyDead)
                {
                    deadList.Add(item);
                }

                projectiles.Clear();
                foreach (Enemy item in enemies)
                {
                    if (item.State == EnemyState.Active)
                    {
                        item.update(gameTime);
                    }
                    else if (item.State == EnemyState.Dead)
                    {
                        newlyDead.Add(item);
                        
                    }
                    else
                    {
                        //Console.WriteLine("Adding ship to removal list");
                        removalList.Add(item);
                        if (item.Type == EnemyType.THOR)
                        {
                            maxThor--;
                            activeThors--;
                            if (maxThor < 1)
                            {
                                thorAlive = false;
                                thorActive = false;
                            }
                            Console.WriteLine("THOR DEAD");
                        }
                    }
                }

                foreach (Enemy item in deadList)
                {
                    newlyDead.Remove(item);
                }

                foreach (Enemy item in removalList)
                {
                    enemies.Remove(item);
                    deadList.Remove(item);
                }

                

                foreach(Enemy item in enemies)
                {
                    if (item.ReadyToShoot)
                    {
                        Texture2D shotSprite;
                        if (item.Type == EnemyType.Wizard)
                            shotSprite = sTexture[shotTexture.Fireball];
                        else if (item.Type == EnemyType.LittleShip)
                            shotSprite = sTexture[shotTexture.Littleshot];
                        else if (item.Type == EnemyType.THOR)
                            shotSprite = sTexture[shotTexture.Hammer];
                        else
                            shotSprite = sTexture[shotTexture.Bigshot];

                        Vector2 velocity = new Vector2(0,rnd.Next(MIN_SHOT_SPEED, MAX_SHOT_SPEED));
                        Vector2 pos = new Vector2(item.Bounds.X + (item.Bounds.Width /2), item.Bounds.Bottom - 10 );
                        Vector2 acceleration = new Vector2(0, 0);
                        float pan = (item.Position.X / viewport.Width) - .5f;
                        if (item.Type == EnemyType.Wizard)
                        {
                            soundsManager.PlaySound("Fireball", pan);
                            Projectile shot = new Projectile(shotSprite, pos, velocity, viewport, WIZARD_DAMAGE, 0, Projectile.Faction.enemy);
                            projectiles.Add(shot);
                            velocity.X = -5;
                            shot = new Projectile(shotSprite, pos, velocity, viewport, WIZARD_DAMAGE, 0, Projectile.Faction.enemy);
                            projectiles.Add(shot);
                            velocity.X = 5;
                            shot = new Projectile(shotSprite, pos, velocity, viewport, WIZARD_DAMAGE, 0, Projectile.Faction.enemy);
                            projectiles.Add(shot);
                        }
                        else if(item.Type == EnemyType.LittleShip)
                        {
                            soundsManager.PlaySound("Explosion", pan);
                            Projectile shot = new Projectile(shotSprite, pos, velocity, viewport, DAMAGE, 0, Projectile.Faction.enemy);
                            projectiles.Add(shot);
                        }
                        else if (item.Type == EnemyType.THOR)
                        {
                            //soundsManager.PlaySound("Explosion");
                            acceleration.Y = .1f;
                            Projectile shot = new Projectile(shotSprite, pos, velocity, acceleration, viewport, 15, .5f, Projectile.Faction.enemy);
                            projectiles.Add(shot);
                            acceleration.X = .1f;
                            shot = new Projectile(shotSprite, pos, velocity, acceleration, viewport, 15, .10f, Projectile.Faction.enemy);
                            projectiles.Add(shot);
                            acceleration.X = .15f;
                            shot = new Projectile(shotSprite, pos, velocity, acceleration, viewport, 15, .15f, Projectile.Faction.enemy);
                            projectiles.Add(shot);
                            acceleration.X = -.1f;
                            shot = new Projectile(shotSprite, pos, velocity, acceleration, viewport, 15, -.10f, Projectile.Faction.enemy);
                            projectiles.Add(shot);
                            acceleration.X = -.15f;
                            shot = new Projectile(shotSprite, pos, velocity, acceleration, viewport, 15, -.15f, Projectile.Faction.enemy);
                            projectiles.Add(shot);
                        }
                        else
                        {
                            soundsManager.PlaySound("Explosion", pan);
                            velocity.X = player.boundRect.Center.X - pos.X;
                            velocity.Y = player.boundRect.Center.Y - pos.Y;
                            velocity.Normalize();
                            velocity.X = velocity.X * 4;
                            velocity.Y = velocity.Y * 4;
                            Projectile shot = new Projectile(shotSprite, pos, velocity, viewport, DAMAGE, 0, Projectile.Faction.enemy);
                            projectiles.Add(shot);
                        }

                        item.ReadyToShoot = false;
                    }
                }

                

                timeSinceLastAdded += (float)gameTime.ElapsedGameTime.TotalSeconds;
                if (timeSinceLastAdded > minTimeSpaceing)
                {
                    if ((rnd.Next(1) == 1 || timeSinceLastAdded > maxTimeSpaceing) && enemies.Count < MAX_ENEMIES)
                    {
                        EnemyType type;
                        Texture2D typeSprite;
                        int enemyChoice = rnd.Next(100);
                        if (thorActive)
                        {
                            if (!(activeThors<maxThor))
                                return;
                            type = EnemyType.THOR;
                            typeSprite = eTexture[enemyTexture.Thor];
                        }
                        else if(wizardActive && enemyChoice <= WIZARD_CHANCE)
                        {
                            type = EnemyType.Wizard;
                            typeSprite = eTexture[enemyTexture.Wizard];
                        }
                        else if (littleActive && enemyChoice > WIZARD_CHANCE && enemyChoice <= LITTLE_CHANCE)
                        {
                            type = EnemyType.LittleShip;
                            typeSprite = eTexture[enemyTexture.LittleShip];
                        }

                        else
                        {
                            type = EnemyType.Ship;
                            typeSprite = eTexture[enemyTexture.Ship];//THOR_LEVEL;
                            //type = EnemyType.Ship;
                            //typeSprite = ship;
                        }


                        Vector2 newPostion = new Vector2();
                        bool isLeft = false;
                        int x = (0 - Enemy.BUFFER_PADDING - typeSprite.Width);
                        int y;
                        if(!HardMode)
                            y = rnd.Next(PLAYFIELD_UPPER_BOUND,PLAYFIELD_LOWER_BOUND);
                        else
                            y = rnd.Next(PLAYFIELD_UPPER_BOUND+ 75, PLAYFIELD_LOWER_BOUND + 25);
                        
                        foreach (Enemy item in enemies)
                        {
                            if ((y >= item.Position.Y - item.Bounds.Height) && y <= item.Bounds.Bottom)
                                return;
                        }

                        if (rnd.Next(2) ==0)
                            isLeft = true;

                        if (isLeft)
                        {
                            x = (viewport.Width + Enemy.BUFFER_PADDING);   
                        }
                        newPostion = new Vector2(x, y);
                            
                        float speed = rnd.Next((int)MIN_SPEED,(int)MAX_SPEED);
                        if (type == EnemyType.Wizard)
                        {
                            speed += WIZARD_SPEED_BONUS;
                            newPostion.Y -= WIZARD_OFFSET;
                        }
                        if (type == EnemyType.THOR)
                        {
                            newPostion.Y -= WIZARD_OFFSET;
                        }
                        if (type == EnemyType.LittleShip)
                        {
                            int shipCount = 3;
                            while (shipCount > 0)
                            {
                                
                                if (removalList.Count > 0)
                                {
                                    Enemy newEnemy = removalList[0];
                                    newEnemy.reset(newPostion, isLeft, speed, typeSprite, type,HardMode);
                                    removalList.Remove(newEnemy);
                                    enemies.Add(newEnemy);
                                }
                                else
                                {
                                    Enemy newEnemy = new Enemy(Enemy.MAX_HEALTH, newPostion, typeSprite, isLeft, speed, viewport, type,HardMode);
                                    enemies.Add(newEnemy);
                                }
                                shipCount--;
                                if(isLeft)
                                    newPostion.X += typeSprite.Width;
                                else
                                    newPostion.X -= typeSprite.Width;
                            }
                        }
                        else
                        {
                            if (removalList.Count > 0)
                            {
                                Enemy newEnemy = removalList[0];
                                newEnemy.reset(newPostion, isLeft, speed, typeSprite, type,HardMode);
                                removalList.Remove(newEnemy);
                                enemies.Add(newEnemy);
                            }
                            else
                            {
                                Enemy newEnemy = new Enemy(Enemy.MAX_HEALTH, newPostion, typeSprite, isLeft, speed, viewport, type,HardMode);
                                enemies.Add(newEnemy);
                            }

                            if (type == EnemyType.THOR)
                            {
                                thorAlive = true;
                                activeThors++;
                                //Console.WriteLine("THOR ALIVE");
                            }
                        }
                        timeSinceLastAdded = 0.0f;
                        if (thorActive && !thorAlive)
                        {
                            //Console.WriteLine("DEACTIAVING THOR");
                            thorActive = false;
                        }

                    }
                }
                
            }
        }

        public void draw(SpriteBatch spriteBatch)
        {
            foreach (Enemy item in enemies)
            {
                item.draw(spriteBatch);
            }
        }

        /// <summary>
        /// reinitilizes enemy manager to its defualt state
        /// </summary>
        public void reset()
        {
            thorAlive = false;
            maxThor = 0;
            activeThors = 0;
            timeSinceLastAdded = 0;
            timeSinceLastIncrease = 0;
            littleActive = false;
            wizardActive = false;
            difficultyLevel = 0;
            thorActive = false;
            HardMode = false;

            this.enemies.Clear();
            this.newlyDead.Clear();
            this.projectiles.Clear();
            this.removalList.Clear();
        }
    }
}
